#coding: utf-8
from square import Box, Dot, HorizontalBar, VerticalBar


class SquareUnitFactory(type):
    u'''方块组合的工厂'''

    def __init__(cls, name, bases, dic):
        super(SquareUnitFactory, cls).__init__(name, bases, dic)
        cls.instances = {}

    def __call__(cls, positions):
        squares = [cls.type(*position) for position in positions]
        if None in squares:
            return None
        mask = 0
        for square in squares:
            if mask & square.mask:
                return None
            mask |= square.mask
        if mask not in cls.instances:
            instance = super(SquareUnitFactory, cls).__call__(squares, mask)
            cls.instances[mask] = instance
        return cls.instances[mask]


class SquareUnit(object):
    __metaclass__ = SquareUnitFactory
    hash = 0

    def __init__(self, squares, mask):
        self.squares = squares
        self.mask = mask
        for square in squares:
            self.hash = self.hash | square.hash
        self.count = self.type.count * len(squares)
        self._nexts = {}

    def next(self, move):
        squares = self.squares[:]
        squares.remove(move.src)
        squares.append(move.dst)
        positions = [(square.x, square.y) for square in squares]
        ncu = self.__class__(positions)
        return ncu

    def nexts(self, mask):
        assert self.mask & mask == self.mask
        if mask not in self._nexts:
            self._nexts[mask] = nexts = []
            for square in self.squares:
                for move in square.moves:
                    if (move.mask & mask) == 0:
                        nexts.append(self.next(move))
                        for move in move.nexts:
                            if (move.mask & mask) == 0:
                                nexts.append(self.next(move))
        return self._nexts[mask]

    def __str__(self):
        return str(self.squares)


class BUnit(SquareUnit):
    type = Box


class DUnit(SquareUnit):
    type = Dot


class VUnit(SquareUnit):
    type = VerticalBar


class HUnit(SquareUnit):
    type = HorizontalBar
